# You should set "fastBCR" folder as working directory before running pipeline.
# knitr::opts_knit$set(root.dir = "THE/PATH/TO/FASTBCR/FOLDER")
knitr::opts_knit$set(root.dir = "~/Documents/Rpackage/fastBCR-1.1") # Replace with your path.
library(fastBCR)
Loading required package: dplyr
Warning: package ‘dplyr’ was built under R version 4.2.3
Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

Loading required package: ggplot2
Loading required package: ggmsa
Registered S3 methods overwritten by 'ggalt':
  method                  from   
  grid.draw.absoluteGrob  ggplot2
  grobHeight.absoluteGrob ggplot2
  grobWidth.absoluteGrob  ggplot2
  grobX.absoluteGrob      ggplot2
  grobY.absoluteGrob      ggplot2
ggmsa v1.4.0  Document: http://yulab-smu.top/ggmsa/

If you use ggmsa in published research, please cite:
L Zhou, T Feng, S Xu, F Gao, TT Lam, Q Wang, T Wu, H Huang, L Zhan, L Li, Y Guan, Z Dai*, G Yu* ggmsa: a visual exploration tool for multiple sequence alignment and associated data. Briefings in Bioinformatics. DOI:10.1093/bib/bbac222
Loading required package: msa
Loading required package: Biostrings
Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, aperm, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find, get,
    grep, grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank,
    rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply, union, unique, unsplit, which.max, which.min

Loading required package: S4Vectors
Loading required package: stats4

Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:dplyr’:

    first, rename

The following objects are masked from ‘package:base’:

    expand.grid, I, unname

Loading required package: IRanges

Attaching package: ‘IRanges’

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

Loading required package: XVector
Loading required package: GenomeInfoDb

Attaching package: ‘Biostrings’

The following object is masked from ‘package:base’:

    strsplit

Loading required package: statnet
Loading required package: tergm
Loading required package: ergm
Warning: package ‘ergm’ was built under R version 4.2.3Loading required package: network
Warning: package ‘network’ was built under R version 4.2.3
‘network’ 1.18.2 (2023-12-04), part of the Statnet Project
* ‘news(package="network")’ for changes since last version
* ‘citation("network")’ for citation information
* ‘https://statnet.org’ for help, support, and other information


‘ergm’ 4.6.0 (2023-12-17), part of the Statnet Project
* ‘news(package="ergm")’ for changes since last version
* ‘citation("ergm")’ for citation information
* ‘https://statnet.org’ for help, support, and other information

‘ergm’ 4 is a major update that introduces some backwards-incompatible changes. Please type ‘news(package="ergm")’ for a list of major
changes.

Loading required package: networkDynamic
Warning: package ‘networkDynamic’ was built under R version 4.2.3
‘networkDynamic’ 0.11.4 (2023-12-10?), part of the Statnet Project
* ‘news(package="networkDynamic")’ for changes since last version
* ‘citation("networkDynamic")’ for citation information
* ‘https://statnet.org’ for help, support, and other information

Registered S3 method overwritten by 'tergm':
  method                   from
  simulate_formula.network ergm

‘tergm’ 4.2.0 (2023-05-30), part of the Statnet Project
* ‘news(package="tergm")’ for changes since last version
* ‘citation("tergm")’ for citation information
* ‘https://statnet.org’ for help, support, and other information


Attaching package: ‘tergm’

The following object is masked from ‘package:ergm’:

    snctrl

Loading required package: ergm.count

‘ergm.count’ 4.1.1 (2022-05-24), part of the Statnet Project
* ‘news(package="ergm.count")’ for changes since last version
* ‘citation("ergm.count")’ for citation information
* ‘https://statnet.org’ for help, support, and other information

Loading required package: sna
Warning: package ‘sna’ was built under R version 4.2.3Loading required package: statnet.common

Attaching package: ‘statnet.common’

The following object is masked from ‘package:ergm’:

    snctrl

The following object is masked from ‘package:Biostrings’:

    order

The following object is masked from ‘package:XVector’:

    order

The following object is masked from ‘package:IRanges’:

    order

The following object is masked from ‘package:S4Vectors’:

    order

The following object is masked from ‘package:BiocGenerics’:

    order

The following objects are masked from ‘package:base’:

    attr, order

sna: Tools for Social Network Analysis
Version 2.7-2 created on 2023-12-05.
copyright (c) 2005, Carter T. Butts, University of California-Irvine
 For citation information, type citation("sna").
 Type help(package="sna") to get started.

Loading required package: tsna

‘statnet’ 2019.6 (2019-06-13), part of the Statnet Project
* ‘news(package="statnet")’ for changes since last version
* ‘citation("statnet")’ for citation information
* ‘https://statnet.org’ for help, support, and other information
### Fast BCR clonal family inference
## 1. Data loading
# Path to the "COVID"/"HC" folder in the "example" folder in fastBCR folder.
COVID_folder_path <- "example/COVID"
HC_folder_path <- "example/HC"
# Load files from "COVID_folder_path"/"HC_folder_path" into list.
# The storage format of data can be in "csv", "tsv", or "Rdata" format.
# The compressed files in the above storage format in "7zip", "cab", "cpio", "iso9660", "lha", "mtree", "shar", "rar", "raw", "tar", "xar", "zip", "warc" format can also be read in.
COVID_raw_data_list <- data.load(folder_path = COVID_folder_path, storage_format = "csv")

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
HC_raw_data_list <- data.load(folder_path = HC_folder_path, storage_format = "csv")

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
## 2. Data preprocessing
# Preprocessing of raw data to meet the input requirements for clonal family inference.
# The input of the function needs to meet the AIRR standard format (containing at least "sequence_id", "v_call", "j_call", and "junction_aa" information).
# "junction" and "c_call" are optional if you want to plot the evolutionary tree or need isotype related (SHM/CSR) analysis.
# Only productive sequences whose junction amino acid lengths between 9 and 26 are reserved.
# The "count_col_name" parameter represents the column name for the count of each sequence which can be "consensus_count", "duplicate_count" or "umi_count" according to your needs.
# It defaults to "NA" which means the original count of the sequence is not taken into account.
# Sequences with the same "v_call", "j_call" and "junction_aa" are considered to be the same clonotype and are merged into one row in processed data.
# The column "clonotype_count" is the number of sequences belonging to each clonotype.
# The column "clone_count" is the sum of the counts (calculated based on "count_col_name" parameter) of the sequences belonging to each clonotype.
# The column "clone_fre" is the frequency version of "clone_count".
# The information of the sequence with the highest count in each clonotype is retained.
# The list "index_match" saves the original indexes of sequences for each clonotype.
COVID_pro_data_list <- data.preprocess(data_list = COVID_raw_data_list, count_col_name = "consensus_count")

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
HC_pro_data_list <- data.preprocess(data_list = HC_raw_data_list, count_col_name = "consensus_count")

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
## 3. BCR clonal family inference
# Fast clonal family inference from preprocessed data.
# The "cluster_thre" parameter represents minimal clustering criteria (minimum number of sequences needed to form a cluster) and defaults to 3.
# For high efficiency, the "cluster_thre" is increased by 1 for every 100,000 entries of input data.
# The "overlap_thre" parameter represents overlap coefficient threshold for merging two clusters, selectable range (0,1) and defaults to 0.1.
# Lower "overlap_thre" may lead to overclustering while higher thresholds may lead to the split of clonal families.
# The "consensus_thre" parameter represents the consensus score threshold for filtering candidates and defaults to 0.8.
# A higher "consensus_thre" means stricter inference of the cluster.
COVID_clusters_list <- data.BCR.clusters(pro_data_list = COVID_pro_data_list, cluster_thre = 3, overlap_thre = 0.1, consensus_thre = 0.8)

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
HC_clusters_list <- data.BCR.clusters(pro_data_list = HC_pro_data_list, cluster_thre = 3, overlap_thre = 0.1, consensus_thre = 0.8)

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
## 4. Classification of clustered and unclustered sequences
# Merge all the clustered sequences in each sample into "clustered_seqs".
# Merge all the unclustered sequences in each sample into "unclustered_seqs".
COVID_seqs_list <- Clustered.seqs(pro_data_list = COVID_pro_data_list, clusters_list = COVID_clusters_list)

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
HC_seqs_list <- Clustered.seqs(pro_data_list = HC_pro_data_list, clusters_list = HC_clusters_list)

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
### Downstream analysis
## 1. Single cluster analysis
## 1.1 Conserved motifs distribution
# Visualization of multiple sequence alignment (MSA) of junction sequences within a cluster.
# The parameter "index" allows you to choose a cluster for visualization.
# The parameter "type" can be "DNA" for deoxyribonucleic acid or "AA" for amino acid.
COVID_01_clusters = COVID_clusters_list$COVID_01
HC_01_clusters = HC_clusters_list$HC_01
msa.plot(bcr_clusters = COVID_01_clusters, index = 200, type = "DNA")
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

msa.plot(bcr_clusters = COVID_01_clusters, index = 200, type = "AA")
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

## 1.2 Sequence logo
# Visualization of sequence logo of junction sequences within a cluster.
seqlogo.plot(bcr_clusters = COVID_01_clusters, index = 200, type = "DNA")
Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as of ggplot2 3.3.4.Coordinate system already present. Adding new coordinate system, which will replace the existing one.

seqlogo.plot(bcr_clusters = COVID_01_clusters, index = 200, type = "AA")
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

## 1.3 Evolutionary tree
# Reconstruct a B cell lineage tree with minimum spanning tree and genotype abundances using ClonalTree.
# The junction of BCR sequences within a cluster will be written as "ClonalFamily_index.fasta" in "ClonalTree/Examples/input" folder.
# ClonalTree uses Python for compilation, so it needs the absolute path of the Python interpreter in the "python_path" parameter.
# ClonalTree returns two files in the "ClonalTree/Examples/output" folder.
# ClonalFamily_index.nk: the reconstructed BCR lineage tree in newick format.
# ClonalFamily_index.nk.csv: a table in csv format, containing the parent relationship and cost.
clonal.tree.generation(bcr_clusters = COVID_01_clusters, index = 200, python_path = "/Users/wangkaixuan/anaconda3/bin/python") # Replace with your path
use default substitution matrix
Parameter setting = useAbundance:  False ; revision:  True ; trim: False
done
# You can use the clonal.tree.plot() function to visualize the evolutionary tree in R.
# The consensus sequence of the cluster is used as the root node of the tree.
# Orange points represent nodes and blue points represent tips.
# Abbreviation of "sequence_id" (last 5 characters) are shown.
# The x-axis shows the absolute genetic distance.
clonal.tree.plot(nk_path = "ClonalTree/Examples/output/ClonalFamily_200.abRT.nk")

## 1.4 Class switch recombination (CSR) network
# Visualization of isotype co-occurrence within clusters within a cluster
# Circle size represents the number of sequences carrying a given isotype.
# Lines connecting two circles indicate the enrichment level of observing switches in the two corresponding immunoglobulin subclasses.
# The enrichment level is the ratio of observed and expected switches if immunoglobulin isotypes are assumed to be independently distributed among cluster.
# Matrix of values of connected edges between clustered sequences in different isotypes is printed.
CSR.cluster.plot(bcr_clusters = COVID_01_clusters, index = 50)
      IGHM IGHD IGHG3 IGHG1 IGHA1 IGHG2 IGHG4 IGHE IGHA2
IGHM     0    0     0     1     1     0     0    0     0
IGHD     0    0     0     0     0     0     0    0     0
IGHG3    0    0     0     0     0     0     0    0     0
IGHG1    1    0     0     0     1     0     0    0     0
IGHA1    1    0     0     1     0     0     0    0     0
IGHG2    0    0     0     0     0     0     0    0     0
IGHG4    0    0     0     0     0     0     0    0     0
IGHE     0    0     0     0     0     0     0    0     0
IGHA2    0    0     0     0     0     0     0    0     0
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2

## 2. Single sample/group analysis
## 2.1 Summary of clusters from a sample
# Summarize the number of clusters, the average size of clusters and the proportion of clustered sequences.
COVID_clusters_summary = Clusters.summary(pro_data_list = COVID_pro_data_list, clusters_list = COVID_clusters_list)
HC_clusters_summary = Clusters.summary(pro_data_list = HC_pro_data_list, clusters_list = HC_clusters_list)
COVID_01_summary = COVID_clusters_summary$COVID_01
print(COVID_01_summary)
$`number of clusters`
[1] 4903

$`average size of clusters`
[1] 8.95

$`number of clustered seqs`
[1] 43862

$`number of all seqs`
[1] 88502

$`proportion of clustered sequences`
[1] "49.56%"
HC_01_summary = HC_clusters_summary$HC_01
print(HC_01_summary)
$`number of clusters`
[1] 798

$`average size of clusters`
[1] 6.74

$`number of clustered seqs`
[1] 5380

$`number of all seqs`
[1] 105364

$`proportion of clustered sequences`
[1] "5.11%"
## 2.2 Visualization of clusters from a sample
# Point diagram showing clusters from a sample where a circle represents a cluster.
# The size and color of the circle represents the size of the cluster.
# The parameter "index" represents the index of the sample for visualization.
Clusters.visualization(pro_data_list = COVID_pro_data_list, clusters_list = COVID_clusters_list, index = 1)

Clusters.visualization(pro_data_list = HC_pro_data_list, clusters_list = HC_clusters_list, index = 1)

## 2.3 V/J gene usage
## 2.3.1 Pie chart: V/J gene
# Pie chart showing the gene usage frequency of clustered sequences.
# The top ten most frequent genes are shown, and the rest are represented by "others".
# The parameter "colname" can be "v_call" for V gene or "j_call" for J gene.
# (1) single sample
COVID_01_clustered_seqs = COVID_seqs_list$clustered_seqs$COVID_01
COVID_01_unclustered_seqs = COVID_seqs_list$unclustered_seqs$COVID_01
HC_01_clustered_seqs = HC_seqs_list$clustered_seqs$HC_01
pie.freq.plot(clustered_seqs = COVID_01_clustered_seqs, colname = "v_call")

pie.freq.plot(clustered_seqs = HC_01_clustered_seqs, colname = "v_call")

# (2) multiple samples in a group.
# All the clustered/unclustered sequences from multiple samples in a group can be merged.
COVID_all_clustered_seqs = NULL
for(i in 1:length(COVID_seqs_list$clustered_seqs)){
  COVID_all_clustered_seqs = rbind(COVID_all_clustered_seqs, COVID_seqs_list$clustered_seqs[[i]])
}
COVID_all_unclustered_seqs = NULL
for(i in 1:length(COVID_seqs_list$unclustered_seqs)){
  COVID_all_unclustered_seqs = rbind(COVID_all_unclustered_seqs, COVID_seqs_list$unclustered_seqs[[i]])
}
HC_all_clustered_seqs = NULL
for(i in 1:length(HC_seqs_list$clustered_seqs)){
  HC_all_clustered_seqs = rbind(HC_all_clustered_seqs, HC_seqs_list$clustered_seqs[[i]])
}
HC_all_unclustered_seqs = NULL
for(i in 1:length(HC_seqs_list$unclustered_seqs)){
  HC_all_unclustered_seqs = rbind(HC_all_unclustered_seqs, HC_seqs_list$unclustered_seqs[[i]])
}
pie.freq.plot(clustered_seqs = COVID_all_clustered_seqs, colname = "v_call")

pie.freq.plot(clustered_seqs = HC_all_clustered_seqs, colname = "v_call")

## 2.3.2 Heatmap: V-J gene pair
# Heatmap showing the V-J gene pair frequency of clustered sequences
# (1) single sample.
vjpair.sample.plot(clustered_seqs = COVID_01_clustered_seqs)
Using Freq as value column: use value.var to override.

# (2) multiple samples in a group.
vjpair.sample.plot(clustered_seqs = COVID_all_clustered_seqs)
Using Freq as value column: use value.var to override.

vjpair.sample.plot(clustered_seqs = HC_all_clustered_seqs)
Using Freq as value column: use value.var to override.

## 2.4 Junction length distribution
# Histogram and density plot showing the length distribution of junction amino acid of clustered sequences.
# (1) single sample
len.sample.plot(clustered_seqs = COVID_01_clustered_seqs)

# (2) multiple samples in a group
len.sample.plot(clustered_seqs = COVID_all_clustered_seqs)

# Density ridges showing the length distributions of junction amino acid of clustered sequences and unclustered sequences.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
# (1) single sample
len.clustered.plot(clustered_seqs = COVID_01_clustered_seqs,
                   unclustered_seqs = COVID_01_unclustered_seqs)
[1] "p-value: <2e-16"
Warning: Ignoring unknown parameters: `size`

# (2) multiple samples in a group
len.clustered.plot(clustered_seqs = COVID_all_clustered_seqs,
                   unclustered_seqs = COVID_all_unclustered_seqs)
[1] "p-value: <2e-16"
Warning: Ignoring unknown parameters: `size`

## 2.5 Class switch recombination (CSR) network
# Visualization of isotype co-occurrence within clusters from a sample.
# Circle size represents the number of sequences carrying a given isotype.
# Lines connecting two circles indicate the enrichment level of observing switches in the two corresponding immunoglobulin subclasses.
# The enrichment level is the ratio of observed and expected switches if immunoglobulin isotypes are assumed to be independently distributed among cluster.
# Matrix of values of connected edges between clustered sequences in different isotypes is printed.
CSR.sample.plot(bcr_clusters = COVID_01_clusters)
      IGHM IGHD IGHG3 IGHG1 IGHA1 IGHG2 IGHG4 IGHE IGHA2
IGHM     0   91    39   465   256    79     1    0    51
IGHD    91    0     4    45    28     8     0    0     7
IGHG3   39    4     0    96    41    32     0    0     6
IGHG1  465   45    96     0   332   165     1    1    50
IGHA1  256   28    41   332     0    80     1    0   108
IGHG2   79    8    32   165    80     0     2    0    56
IGHG4    1    0     0     1     1     2     0    0     0
IGHE     0    0     0     1     0     0     0    0     0
IGHA2   51    7     6    50   108    56     0    0     0

CSR.sample.plot(bcr_clusters = HC_01_clusters)
      IGHM IGHD IGHG3 IGHG1 IGHA1 IGHG2 IGHG4 IGHE IGHA2
IGHM     0  240    11    25    58    51     1    0    36
IGHD   240    0     5    32    42    32     1    0    25
IGHG3   11    5     0    12    16    19     1    0     8
IGHG1   25   32    12     0    72    58     1    0    34
IGHA1   58   42    16    72     0    97     2    0    75
IGHG2   51   32    19    58    97     0     4    0    72
IGHG4    1    1     1     1     2     4     0    0     2
IGHE     0    0     0     0     0     0     0    0     0
IGHA2   36   25     8    34    75    72     2    0     0

### 2.6 Neutralizing antibody (NAb) sequence query
## 2.6.1 Load the public antibody database to get the information of neutralizing antibody (NAb) sequences.
# Here is an example of the Coronavirus Antibody Database (CoV-AbDab).
CoV_AbDab = read.csv("example/CoV-AbDab_130623.csv")
## 2.6.2 NAb query
# Query the corresponding sequence from the public antibody database.
# The parameter "method" represents the CDRH3 matching method.
# It can be "NA" for perfect match, "hamming" for hamming distance or "lv" for Levenshtein distance. Defaults to "NA".
# The parameter "species" can be "Mouse" or "Human". Defaults to "Human".
# The parameter "maxDist" represents the maximum distance allowed for matching when the argument "method" is "hamming" or "lv". Defaults to "NA".
# example to perfect match
human_perfect_match <- NAb.query(bcr_clusters = COVID_01_clusters, AbDab = CoV_AbDab, method = NA, maxDist = NA, species = "Human")
[1] "The query result has 26 rows."
head(human_perfect_match)
# example with perfect match in "Mouse" species
mouse_perfect_match <- NAb.query(bcr_clusters = COVID_01_clusters, AbDab = CoV_AbDab, method = NA, maxDist = NA, species = "Mouse")
[1] "The query result is empty."
# example with fuzzy matching with "hamming" method and max distance of 1
human_hamming_1_match <- NAb.query(bcr_clusters = COVID_01_clusters, AbDab = CoV_AbDab, method = "hamming", maxDist = 1, species = "Human")
[1] "The query result has 37 rows."
## 3. Inter group analysis
## 3.1 V/J gene usage
## 3.1.1 Boxplot: V/J gene
# Boxplot showing the V/J gene usage of the clustered sequences between two groups.
# The parameter "colname" can be "v_call" for V gene or "j_call" for J gene.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
gene.fre.plot(group1_seqs_list = COVID_seqs_list,
              group1_all_clustered_seqs = COVID_all_clustered_seqs,
              group1_label = "COVID-19",
              group2_seqs_list = HC_seqs_list,
              group2_all_clustered_seqs = HC_all_clustered_seqs,
              group2_label = "HC",
              colname = "v_call")

gene.fre.plot(group1_seqs_list = COVID_seqs_list,
              group1_all_clustered_seqs = COVID_all_clustered_seqs,
              group1_label = "COVID-19",
              group2_seqs_list = HC_seqs_list,
              group2_all_clustered_seqs = HC_all_clustered_seqs,
              group2_label = "HC",
              colname = "j_call")

## 3.1.2 Heatmap: V-J gene pair
# Heatmap showing the fold change of V-J gene pair frequency of clustered sequences between two groups.
# Log fold change (log FC) is calculated as the log2 ratio of the average values between group1 and group2 samples.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
# FDR correction was performed with the Benjamini–Hochberg procedure.
# The V-J gene pair frequency of samples with a frequency less than the minimum value (1‰) is set to the minimum value.
vjpair.group.plot(group1_seqs_list = COVID_seqs_list,
                  group1_all_clustered_seqs = COVID_all_clustered_seqs,
                  group1_label = "COVID-19",
                  group2_seqs_list = HC_seqs_list,
                  group2_all_clustered_seqs = HC_all_clustered_seqs,
                  group2_label = "HC")

## 3.2 Junction length
# Density ridges showing the length distribution of junction amino acid of clustered sequences between two groups.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
len.group.plot(group1_all_clustered_seqs = COVID_all_clustered_seqs, group1_label = "COVID-19",
               group2_all_clustered_seqs = HC_all_clustered_seqs, group2_label = "HC")
[1] "p-value: <2e-16"
Warning: Ignoring unknown parameters: `size`

## 3.3 Diversity analysis
## 3.3.1 Number and size of clusters
# Bubble plot showing the size and number of clusters between two groups.
clu.size.plot(clusters_list1 = COVID_clusters_list, group1_label = "COVID-19",
              clusters_list2 = HC_clusters_list, group2_label = "HC")
[1] "p-value: 1.1e-15"

## 3.3.2 Tcf20 score
# Tcf20 score represents the proportion of sequences attributed to the top 20 clonal families out of the total number of BCR sequences.
# Boxplot showing the Tcf20 scores between two groups.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
Tcf20.plot(clusters_list1 = COVID_clusters_list, group1_label = "COVID-19",
           clusters_list2 = HC_clusters_list, group2_label = "HC")
[1] "p-value: 0.0079"

## 3.4 Somatic hypermutation (SHM) analysis
# Calculate the average SHM ratio of all clusters in each sample.
# The calculation of SHM ratios may take a while.
SHM_df = SHM.calculation(clusters_list1 = COVID_clusters_list, group1_label = "COVID-19",
                         clusters_list2 = HC_clusters_list, group2_label = "HC")
[1] "group1 processing:"

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%[1] "group2 processing:"

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
# Boxplot showing the SHM ratios between two groups.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
SHM.plot(SHM_df = SHM_df)
[1] "p-value: 0.0079"

# Calculate the SHM ratios of clustered sequences in different isotypes in each sample.
# The calculation of SHM ratios may take a while.
SHM_iso_df = SHM.iso.calculation(clusters_list1 = COVID_clusters_list, group1_label = "COVID-19",
                                 clusters_list2 = HC_clusters_list, group2_label = "HC")
[1] "group1 processing:"

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%[1] "group2 processing:"

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
# Boxplot showing the SHM ratios of clustered sequences in different isotypes between two groups.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
SHM.iso.plot(SHM_iso_df = SHM_iso_df)
 [1] "COVID-19_IGHD~COVID-19_IGHM p-value: 0.0079" "COVID-19_IGHD~COVID-19_IGHA p-value: 0.0079" "COVID-19_IGHD~COVID-19_IGHG p-value: 0.0079"
 [4] "COVID-19_IGHD~HC_IGHA p-value: 0.0079"       "COVID-19_IGHD~HC_IGHG p-value: 0.0079"       "COVID-19_IGHM~HC_IGHD p-value: 0.0079"      
 [7] "COVID-19_IGHM~HC_IGHM p-value: 0.0079"       "COVID-19_IGHM~HC_IGHA p-value: 0.0079"       "COVID-19_IGHM~HC_IGHG p-value: 0.0079"      
[10] "COVID-19_IGHA~HC_IGHD p-value: 0.0079"       "COVID-19_IGHA~HC_IGHM p-value: 0.0079"       "COVID-19_IGHA~HC_IGHA p-value: 0.0159"      
[13] "COVID-19_IGHG~HC_IGHD p-value: 0.0079"       "COVID-19_IGHG~HC_IGHM p-value: 0.0079"       "COVID-19_IGHG~HC_IGHA p-value: 0.0159"      
[16] "COVID-19_IGHG~HC_IGHG p-value: 0.0317"       "HC_IGHD~HC_IGHM p-value: 0.0317"             "HC_IGHD~HC_IGHA p-value: 0.0079"            
[19] "HC_IGHD~HC_IGHG p-value: 0.0079"             "HC_IGHM~HC_IGHA p-value: 0.0079"             "HC_IGHM~HC_IGHG p-value: 0.0079"            

### 3.5 NAb ratio calculation
## 3.5.1 Load the public antibody database to get the information of neutralizing antibody (NAb) sequences.
# Here is an example of the Coronavirus Antibody Database (CoV-AbDab).
CoV_AbDab = read.csv("example/CoV-AbDab_130623.csv")
# Obtain the IGHV gene, IGHJ gene and CDRH3 of all antibody sequences
v = sapply(strsplit(CoV_AbDab$Heavy.V.Gene, " "), function(x) x[1])
j = sapply(strsplit(CoV_AbDab$Heavy.J.Gene, " "), function(x) x[1])
cdr3 = sapply(strsplit(CoV_AbDab$CDRH3, " "), function(x) x[1])
vjcdr3 = unique(paste(v, j, cdr3))
## 3.5.2 NAb ratio calculation
# NAb ratio is established as an indicator of the proportional prevalence of neutralizing antibody sequences within expanded clonotypes in each sample.
# It is defined as the fraction of the number of NAb sequences within clonal families to the total number of NAb sequences present in each sample.
NAb_ratio_df = NAb.ratio.calculation(pro_data_list1 = COVID_pro_data_list, clusters_list1 = COVID_clusters_list, group1_label = "COVID-19",
                                     pro_data_list2 = HC_pro_data_list, clusters_list2 = HC_clusters_list, group2_label = "HC", NAb_vjcdr3 = vjcdr3)
[1] "group1 processing:"

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%[1] "group2 processing:"

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |=============================                                                                                                                     |  20%
  |                                                                                                                                                        
  |==========================================================                                                                                        |  40%
  |                                                                                                                                                        
  |========================================================================================                                                          |  60%
  |                                                                                                                                                        
  |=====================================================================================================================                             |  80%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%
# Boxplot showing the NAb ratios between the two groups.
# Statistical comparisons are carried out by the two-sided Wilcoxon rank-sum test.
NAb.ratio.plot(NAb_ratio_df)
[1] "p-value: 0.025"

LS0tCnRpdGxlOiAiZmFzdEJDUiBwaXBlbGluZSBub3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0KIyBZb3Ugc2hvdWxkIHNldCAiZmFzdEJDUiIgZm9sZGVyIGFzIHdvcmtpbmcgZGlyZWN0b3J5IGJlZm9yZSBydW5uaW5nIHBpcGVsaW5lLgojIGtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIlRIRS9QQVRIL1RPL0ZBU1RCQ1IvRk9MREVSIikKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAifi9Eb2N1bWVudHMvUnBhY2thZ2UvZmFzdEJDUi0xLjEiKSAjIFJlcGxhY2Ugd2l0aCB5b3VyIHBhdGguCmBgYApgYGB7cn0KbGlicmFyeShmYXN0QkNSKQpgYGAKCmBgYHtyfQojIyMgRmFzdCBCQ1IgY2xvbmFsIGZhbWlseSBpbmZlcmVuY2UKIyMgMS4gRGF0YSBsb2FkaW5nCiMgUGF0aCB0byB0aGUgIkNPVklEIi8iSEMiIGZvbGRlciBpbiB0aGUgImV4YW1wbGUiIGZvbGRlciBpbiBmYXN0QkNSIGZvbGRlci4KQ09WSURfZm9sZGVyX3BhdGggPC0gImV4YW1wbGUvQ09WSUQiCkhDX2ZvbGRlcl9wYXRoIDwtICJleGFtcGxlL0hDIgpgYGAKYGBge3J9CiMgTG9hZCBmaWxlcyBmcm9tICJDT1ZJRF9mb2xkZXJfcGF0aCIvIkhDX2ZvbGRlcl9wYXRoIiBpbnRvIGxpc3QuCiMgVGhlIHN0b3JhZ2UgZm9ybWF0IG9mIGRhdGEgY2FuIGJlIGluICJjc3YiLCAidHN2Iiwgb3IgIlJkYXRhIiBmb3JtYXQuCiMgVGhlIGNvbXByZXNzZWQgZmlsZXMgaW4gdGhlIGFib3ZlIHN0b3JhZ2UgZm9ybWF0IGluICI3emlwIiwgImNhYiIsICJjcGlvIiwgImlzbzk2NjAiLCAibGhhIiwgIm10cmVlIiwgInNoYXIiLCAicmFyIiwgInJhdyIsICJ0YXIiLCAieGFyIiwgInppcCIsICJ3YXJjIiBmb3JtYXQgY2FuIGFsc28gYmUgcmVhZCBpbi4KQ09WSURfcmF3X2RhdGFfbGlzdCA8LSBkYXRhLmxvYWQoZm9sZGVyX3BhdGggPSBDT1ZJRF9mb2xkZXJfcGF0aCwgc3RvcmFnZV9mb3JtYXQgPSAiY3N2IikKSENfcmF3X2RhdGFfbGlzdCA8LSBkYXRhLmxvYWQoZm9sZGVyX3BhdGggPSBIQ19mb2xkZXJfcGF0aCwgc3RvcmFnZV9mb3JtYXQgPSAiY3N2IikKYGBgCgpgYGB7cn0KIyMgMi4gRGF0YSBwcmVwcm9jZXNzaW5nCiMgUHJlcHJvY2Vzc2luZyBvZiByYXcgZGF0YSB0byBtZWV0IHRoZSBpbnB1dCByZXF1aXJlbWVudHMgZm9yIGNsb25hbCBmYW1pbHkgaW5mZXJlbmNlLgojIFRoZSBpbnB1dCBvZiB0aGUgZnVuY3Rpb24gbmVlZHMgdG8gbWVldCB0aGUgQUlSUiBzdGFuZGFyZCBmb3JtYXQgKGNvbnRhaW5pbmcgYXQgbGVhc3QgInNlcXVlbmNlX2lkIiwgInZfY2FsbCIsICJqX2NhbGwiLCBhbmQgImp1bmN0aW9uX2FhIiBpbmZvcm1hdGlvbikuCiMgImp1bmN0aW9uIiBhbmQgImNfY2FsbCIgYXJlIG9wdGlvbmFsIGlmIHlvdSB3YW50IHRvIHBsb3QgdGhlIGV2b2x1dGlvbmFyeSB0cmVlIG9yIG5lZWQgaXNvdHlwZSByZWxhdGVkIChTSE0vQ1NSKSBhbmFseXNpcy4KIyBPbmx5IHByb2R1Y3RpdmUgc2VxdWVuY2VzIHdob3NlIGp1bmN0aW9uIGFtaW5vIGFjaWQgbGVuZ3RocyBiZXR3ZWVuIDkgYW5kIDI2IGFyZSByZXNlcnZlZC4KIyBUaGUgImNvdW50X2NvbF9uYW1lIiBwYXJhbWV0ZXIgcmVwcmVzZW50cyB0aGUgY29sdW1uIG5hbWUgZm9yIHRoZSBjb3VudCBvZiBlYWNoIHNlcXVlbmNlIHdoaWNoIGNhbiBiZSAiY29uc2Vuc3VzX2NvdW50IiwgImR1cGxpY2F0ZV9jb3VudCIgb3IgInVtaV9jb3VudCIgYWNjb3JkaW5nIHRvIHlvdXIgbmVlZHMuCiMgSXQgZGVmYXVsdHMgdG8gIk5BIiB3aGljaCBtZWFucyB0aGUgb3JpZ2luYWwgY291bnQgb2YgdGhlIHNlcXVlbmNlIGlzIG5vdCB0YWtlbiBpbnRvIGFjY291bnQuCiMgU2VxdWVuY2VzIHdpdGggdGhlIHNhbWUgInZfY2FsbCIsICJqX2NhbGwiIGFuZCAianVuY3Rpb25fYWEiIGFyZSBjb25zaWRlcmVkIHRvIGJlIHRoZSBzYW1lIGNsb25vdHlwZSBhbmQgYXJlIG1lcmdlZCBpbnRvIG9uZSByb3cgaW4gcHJvY2Vzc2VkIGRhdGEuCiMgVGhlIGNvbHVtbiAiY2xvbm90eXBlX2NvdW50IiBpcyB0aGUgbnVtYmVyIG9mIHNlcXVlbmNlcyBiZWxvbmdpbmcgdG8gZWFjaCBjbG9ub3R5cGUuCiMgVGhlIGNvbHVtbiAiY2xvbmVfY291bnQiIGlzIHRoZSBzdW0gb2YgdGhlIGNvdW50cyAoY2FsY3VsYXRlZCBiYXNlZCBvbiAiY291bnRfY29sX25hbWUiIHBhcmFtZXRlcikgb2YgdGhlIHNlcXVlbmNlcyBiZWxvbmdpbmcgdG8gZWFjaCBjbG9ub3R5cGUuCiMgVGhlIGNvbHVtbiAiY2xvbmVfZnJlIiBpcyB0aGUgZnJlcXVlbmN5IHZlcnNpb24gb2YgImNsb25lX2NvdW50Ii4KIyBUaGUgaW5mb3JtYXRpb24gb2YgdGhlIHNlcXVlbmNlIHdpdGggdGhlIGhpZ2hlc3QgY291bnQgaW4gZWFjaCBjbG9ub3R5cGUgaXMgcmV0YWluZWQuCiMgVGhlIGxpc3QgImluZGV4X21hdGNoIiBzYXZlcyB0aGUgb3JpZ2luYWwgaW5kZXhlcyBvZiBzZXF1ZW5jZXMgZm9yIGVhY2ggY2xvbm90eXBlLgpDT1ZJRF9wcm9fZGF0YV9saXN0IDwtIGRhdGEucHJlcHJvY2VzcyhkYXRhX2xpc3QgPSBDT1ZJRF9yYXdfZGF0YV9saXN0LCBjb3VudF9jb2xfbmFtZSA9ICJjb25zZW5zdXNfY291bnQiKQpIQ19wcm9fZGF0YV9saXN0IDwtIGRhdGEucHJlcHJvY2VzcyhkYXRhX2xpc3QgPSBIQ19yYXdfZGF0YV9saXN0LCBjb3VudF9jb2xfbmFtZSA9ICJjb25zZW5zdXNfY291bnQiKQpgYGAKCmBgYHtyfQojIyAzLiBCQ1IgY2xvbmFsIGZhbWlseSBpbmZlcmVuY2UKIyBGYXN0IGNsb25hbCBmYW1pbHkgaW5mZXJlbmNlIGZyb20gcHJlcHJvY2Vzc2VkIGRhdGEuCiMgVGhlICJjbHVzdGVyX3RocmUiIHBhcmFtZXRlciByZXByZXNlbnRzIG1pbmltYWwgY2x1c3RlcmluZyBjcml0ZXJpYSAobWluaW11bSBudW1iZXIgb2Ygc2VxdWVuY2VzIG5lZWRlZCB0byBmb3JtIGEgY2x1c3RlcikgYW5kIGRlZmF1bHRzIHRvIDMuCiMgRm9yIGhpZ2ggZWZmaWNpZW5jeSwgdGhlICJjbHVzdGVyX3RocmUiIGlzIGluY3JlYXNlZCBieSAxIGZvciBldmVyeSAxMDAsMDAwIGVudHJpZXMgb2YgaW5wdXQgZGF0YS4KIyBUaGUgIm92ZXJsYXBfdGhyZSIgcGFyYW1ldGVyIHJlcHJlc2VudHMgb3ZlcmxhcCBjb2VmZmljaWVudCB0aHJlc2hvbGQgZm9yIG1lcmdpbmcgdHdvIGNsdXN0ZXJzLCBzZWxlY3RhYmxlIHJhbmdlICgwLDEpIGFuZCBkZWZhdWx0cyB0byAwLjEuCiMgTG93ZXIgIm92ZXJsYXBfdGhyZSIgbWF5IGxlYWQgdG8gb3ZlcmNsdXN0ZXJpbmcgd2hpbGUgaGlnaGVyIHRocmVzaG9sZHMgbWF5IGxlYWQgdG8gdGhlIHNwbGl0IG9mIGNsb25hbCBmYW1pbGllcy4KIyBUaGUgImNvbnNlbnN1c190aHJlIiBwYXJhbWV0ZXIgcmVwcmVzZW50cyB0aGUgY29uc2Vuc3VzIHNjb3JlIHRocmVzaG9sZCBmb3IgZmlsdGVyaW5nIGNhbmRpZGF0ZXMgYW5kIGRlZmF1bHRzIHRvIDAuOC4KIyBBIGhpZ2hlciAiY29uc2Vuc3VzX3RocmUiIG1lYW5zIHN0cmljdGVyIGluZmVyZW5jZSBvZiB0aGUgY2x1c3Rlci4KQ09WSURfY2x1c3RlcnNfbGlzdCA8LSBkYXRhLkJDUi5jbHVzdGVycyhwcm9fZGF0YV9saXN0ID0gQ09WSURfcHJvX2RhdGFfbGlzdCwgY2x1c3Rlcl90aHJlID0gMywgb3ZlcmxhcF90aHJlID0gMC4xLCBjb25zZW5zdXNfdGhyZSA9IDAuOCkKSENfY2x1c3RlcnNfbGlzdCA8LSBkYXRhLkJDUi5jbHVzdGVycyhwcm9fZGF0YV9saXN0ID0gSENfcHJvX2RhdGFfbGlzdCwgY2x1c3Rlcl90aHJlID0gMywgb3ZlcmxhcF90aHJlID0gMC4xLCBjb25zZW5zdXNfdGhyZSA9IDAuOCkKYGBgCgpgYGB7cn0KIyMgNC4gQ2xhc3NpZmljYXRpb24gb2YgY2x1c3RlcmVkIGFuZCB1bmNsdXN0ZXJlZCBzZXF1ZW5jZXMKIyBNZXJnZSBhbGwgdGhlIGNsdXN0ZXJlZCBzZXF1ZW5jZXMgaW4gZWFjaCBzYW1wbGUgaW50byAiY2x1c3RlcmVkX3NlcXMiLgojIE1lcmdlIGFsbCB0aGUgdW5jbHVzdGVyZWQgc2VxdWVuY2VzIGluIGVhY2ggc2FtcGxlIGludG8gInVuY2x1c3RlcmVkX3NlcXMiLgpDT1ZJRF9zZXFzX2xpc3QgPC0gQ2x1c3RlcmVkLnNlcXMocHJvX2RhdGFfbGlzdCA9IENPVklEX3Byb19kYXRhX2xpc3QsIGNsdXN0ZXJzX2xpc3QgPSBDT1ZJRF9jbHVzdGVyc19saXN0KQpIQ19zZXFzX2xpc3QgPC0gQ2x1c3RlcmVkLnNlcXMocHJvX2RhdGFfbGlzdCA9IEhDX3Byb19kYXRhX2xpc3QsIGNsdXN0ZXJzX2xpc3QgPSBIQ19jbHVzdGVyc19saXN0KQpgYGAKCgpgYGB7cn0KIyMjIERvd25zdHJlYW0gYW5hbHlzaXMKIyMgMS4gU2luZ2xlIGNsdXN0ZXIgYW5hbHlzaXMKIyMgMS4xIENvbnNlcnZlZCBtb3RpZnMgZGlzdHJpYnV0aW9uCiMgVmlzdWFsaXphdGlvbiBvZiBtdWx0aXBsZSBzZXF1ZW5jZSBhbGlnbm1lbnQgKE1TQSkgb2YganVuY3Rpb24gc2VxdWVuY2VzIHdpdGhpbiBhIGNsdXN0ZXIuCiMgVGhlIHBhcmFtZXRlciAiaW5kZXgiIGFsbG93cyB5b3UgdG8gY2hvb3NlIGEgY2x1c3RlciBmb3IgdmlzdWFsaXphdGlvbi4KIyBUaGUgcGFyYW1ldGVyICJ0eXBlIiBjYW4gYmUgIkROQSIgZm9yIGRlb3h5cmlib251Y2xlaWMgYWNpZCBvciAiQUEiIGZvciBhbWlubyBhY2lkLgpDT1ZJRF8wMV9jbHVzdGVycyA9IENPVklEX2NsdXN0ZXJzX2xpc3QkQ09WSURfMDEKSENfMDFfY2x1c3RlcnMgPSBIQ19jbHVzdGVyc19saXN0JEhDXzAxCm1zYS5wbG90KGJjcl9jbHVzdGVycyA9IENPVklEXzAxX2NsdXN0ZXJzLCBpbmRleCA9IDIwMCwgdHlwZSA9ICJETkEiKQptc2EucGxvdChiY3JfY2x1c3RlcnMgPSBDT1ZJRF8wMV9jbHVzdGVycywgaW5kZXggPSAyMDAsIHR5cGUgPSAiQUEiKQpgYGAKYGBge3J9CiMjIDEuMiBTZXF1ZW5jZSBsb2dvCiMgVmlzdWFsaXphdGlvbiBvZiBzZXF1ZW5jZSBsb2dvIG9mIGp1bmN0aW9uIHNlcXVlbmNlcyB3aXRoaW4gYSBjbHVzdGVyLgpzZXFsb2dvLnBsb3QoYmNyX2NsdXN0ZXJzID0gQ09WSURfMDFfY2x1c3RlcnMsIGluZGV4ID0gMjAwLCB0eXBlID0gIkROQSIpCnNlcWxvZ28ucGxvdChiY3JfY2x1c3RlcnMgPSBDT1ZJRF8wMV9jbHVzdGVycywgaW5kZXggPSAyMDAsIHR5cGUgPSAiQUEiKQpgYGAKCmBgYHtyfQojIyAxLjMgRXZvbHV0aW9uYXJ5IHRyZWUKIyBSZWNvbnN0cnVjdCBhIEIgY2VsbCBsaW5lYWdlIHRyZWUgd2l0aCBtaW5pbXVtIHNwYW5uaW5nIHRyZWUgYW5kIGdlbm90eXBlIGFidW5kYW5jZXMgdXNpbmcgQ2xvbmFsVHJlZS4KIyBUaGUganVuY3Rpb24gb2YgQkNSIHNlcXVlbmNlcyB3aXRoaW4gYSBjbHVzdGVyIHdpbGwgYmUgd3JpdHRlbiBhcyAiQ2xvbmFsRmFtaWx5X2luZGV4LmZhc3RhIiBpbiAiQ2xvbmFsVHJlZS9FeGFtcGxlcy9pbnB1dCIgZm9sZGVyLgojIENsb25hbFRyZWUgdXNlcyBQeXRob24gZm9yIGNvbXBpbGF0aW9uLCBzbyBpdCBuZWVkcyB0aGUgYWJzb2x1dGUgcGF0aCBvZiB0aGUgUHl0aG9uIGludGVycHJldGVyIGluIHRoZSAicHl0aG9uX3BhdGgiIHBhcmFtZXRlci4KIyBDbG9uYWxUcmVlIHJldHVybnMgdHdvIGZpbGVzIGluIHRoZSAiQ2xvbmFsVHJlZS9FeGFtcGxlcy9vdXRwdXQiIGZvbGRlci4KIyBDbG9uYWxGYW1pbHlfaW5kZXgubms6IHRoZSByZWNvbnN0cnVjdGVkIEJDUiBsaW5lYWdlIHRyZWUgaW4gbmV3aWNrIGZvcm1hdC4KIyBDbG9uYWxGYW1pbHlfaW5kZXgubmsuY3N2OiBhIHRhYmxlIGluIGNzdiBmb3JtYXQsIGNvbnRhaW5pbmcgdGhlIHBhcmVudCByZWxhdGlvbnNoaXAgYW5kIGNvc3QuCmNsb25hbC50cmVlLmdlbmVyYXRpb24oYmNyX2NsdXN0ZXJzID0gQ09WSURfMDFfY2x1c3RlcnMsIGluZGV4ID0gMjAwLCBweXRob25fcGF0aCA9ICIvVXNlcnMvd2FuZ2thaXh1YW4vYW5hY29uZGEzL2Jpbi9weXRob24iKSAjIFJlcGxhY2Ugd2l0aCB5b3VyIHBhdGgKIyBZb3UgY2FuIHVzZSB0aGUgY2xvbmFsLnRyZWUucGxvdCgpIGZ1bmN0aW9uIHRvIHZpc3VhbGl6ZSB0aGUgZXZvbHV0aW9uYXJ5IHRyZWUgaW4gUi4KIyBUaGUgY29uc2Vuc3VzIHNlcXVlbmNlIG9mIHRoZSBjbHVzdGVyIGlzIHVzZWQgYXMgdGhlIHJvb3Qgbm9kZSBvZiB0aGUgdHJlZS4KIyBPcmFuZ2UgcG9pbnRzIHJlcHJlc2VudCBub2RlcyBhbmQgYmx1ZSBwb2ludHMgcmVwcmVzZW50IHRpcHMuCiMgQWJicmV2aWF0aW9uIG9mICJzZXF1ZW5jZV9pZCIgKGxhc3QgNSBjaGFyYWN0ZXJzKSBhcmUgc2hvd24uCiMgVGhlIHgtYXhpcyBzaG93cyB0aGUgYWJzb2x1dGUgZ2VuZXRpYyBkaXN0YW5jZS4KY2xvbmFsLnRyZWUucGxvdChua19wYXRoID0gIkNsb25hbFRyZWUvRXhhbXBsZXMvb3V0cHV0L0Nsb25hbEZhbWlseV8yMDAuYWJSVC5uayIpCmBgYAoKCmBgYHtyfQojIyAxLjQgQ2xhc3Mgc3dpdGNoIHJlY29tYmluYXRpb24gKENTUikgbmV0d29yawojIFZpc3VhbGl6YXRpb24gb2YgaXNvdHlwZSBjby1vY2N1cnJlbmNlIHdpdGhpbiBjbHVzdGVycyB3aXRoaW4gYSBjbHVzdGVyCiMgQ2lyY2xlIHNpemUgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIHNlcXVlbmNlcyBjYXJyeWluZyBhIGdpdmVuIGlzb3R5cGUuCiMgTGluZXMgY29ubmVjdGluZyB0d28gY2lyY2xlcyBpbmRpY2F0ZSB0aGUgZW5yaWNobWVudCBsZXZlbCBvZiBvYnNlcnZpbmcgc3dpdGNoZXMgaW4gdGhlIHR3byBjb3JyZXNwb25kaW5nIGltbXVub2dsb2J1bGluIHN1YmNsYXNzZXMuCiMgVGhlIGVucmljaG1lbnQgbGV2ZWwgaXMgdGhlIHJhdGlvIG9mIG9ic2VydmVkIGFuZCBleHBlY3RlZCBzd2l0Y2hlcyBpZiBpbW11bm9nbG9idWxpbiBpc290eXBlcyBhcmUgYXNzdW1lZCB0byBiZSBpbmRlcGVuZGVudGx5IGRpc3RyaWJ1dGVkIGFtb25nIGNsdXN0ZXIuCiMgTWF0cml4IG9mIHZhbHVlcyBvZiBjb25uZWN0ZWQgZWRnZXMgYmV0d2VlbiBjbHVzdGVyZWQgc2VxdWVuY2VzIGluIGRpZmZlcmVudCBpc290eXBlcyBpcyBwcmludGVkLgpDU1IuY2x1c3Rlci5wbG90KGJjcl9jbHVzdGVycyA9IENPVklEXzAxX2NsdXN0ZXJzLCBpbmRleCA9IDUwKQpgYGAKYGBge3J9CiMjIDIuIFNpbmdsZSBzYW1wbGUvZ3JvdXAgYW5hbHlzaXMKIyMgMi4xIFN1bW1hcnkgb2YgY2x1c3RlcnMgZnJvbSBhIHNhbXBsZQojIFN1bW1hcml6ZSB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzLCB0aGUgYXZlcmFnZSBzaXplIG9mIGNsdXN0ZXJzIGFuZCB0aGUgcHJvcG9ydGlvbiBvZiBjbHVzdGVyZWQgc2VxdWVuY2VzLgpDT1ZJRF9jbHVzdGVyc19zdW1tYXJ5ID0gQ2x1c3RlcnMuc3VtbWFyeShwcm9fZGF0YV9saXN0ID0gQ09WSURfcHJvX2RhdGFfbGlzdCwgY2x1c3RlcnNfbGlzdCA9IENPVklEX2NsdXN0ZXJzX2xpc3QpCkhDX2NsdXN0ZXJzX3N1bW1hcnkgPSBDbHVzdGVycy5zdW1tYXJ5KHByb19kYXRhX2xpc3QgPSBIQ19wcm9fZGF0YV9saXN0LCBjbHVzdGVyc19saXN0ID0gSENfY2x1c3RlcnNfbGlzdCkKQ09WSURfMDFfc3VtbWFyeSA9IENPVklEX2NsdXN0ZXJzX3N1bW1hcnkkQ09WSURfMDEKcHJpbnQoQ09WSURfMDFfc3VtbWFyeSkKSENfMDFfc3VtbWFyeSA9IEhDX2NsdXN0ZXJzX3N1bW1hcnkkSENfMDEKcHJpbnQoSENfMDFfc3VtbWFyeSkKYGBgCmBgYHtyfQojIyAyLjIgVmlzdWFsaXphdGlvbiBvZiBjbHVzdGVycyBmcm9tIGEgc2FtcGxlCiMgUG9pbnQgZGlhZ3JhbSBzaG93aW5nIGNsdXN0ZXJzIGZyb20gYSBzYW1wbGUgd2hlcmUgYSBjaXJjbGUgcmVwcmVzZW50cyBhIGNsdXN0ZXIuCiMgVGhlIHNpemUgYW5kIGNvbG9yIG9mIHRoZSBjaXJjbGUgcmVwcmVzZW50cyB0aGUgc2l6ZSBvZiB0aGUgY2x1c3Rlci4KIyBUaGUgcGFyYW1ldGVyICJpbmRleCIgcmVwcmVzZW50cyB0aGUgaW5kZXggb2YgdGhlIHNhbXBsZSBmb3IgdmlzdWFsaXphdGlvbi4KQ2x1c3RlcnMudmlzdWFsaXphdGlvbihwcm9fZGF0YV9saXN0ID0gQ09WSURfcHJvX2RhdGFfbGlzdCwgY2x1c3RlcnNfbGlzdCA9IENPVklEX2NsdXN0ZXJzX2xpc3QsIGluZGV4ID0gMSkKQ2x1c3RlcnMudmlzdWFsaXphdGlvbihwcm9fZGF0YV9saXN0ID0gSENfcHJvX2RhdGFfbGlzdCwgY2x1c3RlcnNfbGlzdCA9IEhDX2NsdXN0ZXJzX2xpc3QsIGluZGV4ID0gMSkKYGBgCgpgYGB7cn0KIyMgMi4zIFYvSiBnZW5lIHVzYWdlCiMjIDIuMy4xIFBpZSBjaGFydDogVi9KIGdlbmUKIyBQaWUgY2hhcnQgc2hvd2luZyB0aGUgZ2VuZSB1c2FnZSBmcmVxdWVuY3kgb2YgY2x1c3RlcmVkIHNlcXVlbmNlcy4KIyBUaGUgdG9wIHRlbiBtb3N0IGZyZXF1ZW50IGdlbmVzIGFyZSBzaG93biwgYW5kIHRoZSByZXN0IGFyZSByZXByZXNlbnRlZCBieSAib3RoZXJzIi4KIyBUaGUgcGFyYW1ldGVyICJjb2xuYW1lIiBjYW4gYmUgInZfY2FsbCIgZm9yIFYgZ2VuZSBvciAial9jYWxsIiBmb3IgSiBnZW5lLgojICgxKSBzaW5nbGUgc2FtcGxlCkNPVklEXzAxX2NsdXN0ZXJlZF9zZXFzID0gQ09WSURfc2Vxc19saXN0JGNsdXN0ZXJlZF9zZXFzJENPVklEXzAxCkNPVklEXzAxX3VuY2x1c3RlcmVkX3NlcXMgPSBDT1ZJRF9zZXFzX2xpc3QkdW5jbHVzdGVyZWRfc2VxcyRDT1ZJRF8wMQpIQ18wMV9jbHVzdGVyZWRfc2VxcyA9IEhDX3NlcXNfbGlzdCRjbHVzdGVyZWRfc2VxcyRIQ18wMQpwaWUuZnJlcS5wbG90KGNsdXN0ZXJlZF9zZXFzID0gQ09WSURfMDFfY2x1c3RlcmVkX3NlcXMsIGNvbG5hbWUgPSAidl9jYWxsIikKcGllLmZyZXEucGxvdChjbHVzdGVyZWRfc2VxcyA9IEhDXzAxX2NsdXN0ZXJlZF9zZXFzLCBjb2xuYW1lID0gInZfY2FsbCIpCmBgYApgYGB7cn0KIyAoMikgbXVsdGlwbGUgc2FtcGxlcyBpbiBhIGdyb3VwLgojIEFsbCB0aGUgY2x1c3RlcmVkL3VuY2x1c3RlcmVkIHNlcXVlbmNlcyBmcm9tIG11bHRpcGxlIHNhbXBsZXMgaW4gYSBncm91cCBjYW4gYmUgbWVyZ2VkLgpDT1ZJRF9hbGxfY2x1c3RlcmVkX3NlcXMgPSBOVUxMCmZvcihpIGluIDE6bGVuZ3RoKENPVklEX3NlcXNfbGlzdCRjbHVzdGVyZWRfc2VxcykpewogIENPVklEX2FsbF9jbHVzdGVyZWRfc2VxcyA9IHJiaW5kKENPVklEX2FsbF9jbHVzdGVyZWRfc2VxcywgQ09WSURfc2Vxc19saXN0JGNsdXN0ZXJlZF9zZXFzW1tpXV0pCn0KQ09WSURfYWxsX3VuY2x1c3RlcmVkX3NlcXMgPSBOVUxMCmZvcihpIGluIDE6bGVuZ3RoKENPVklEX3NlcXNfbGlzdCR1bmNsdXN0ZXJlZF9zZXFzKSl7CiAgQ09WSURfYWxsX3VuY2x1c3RlcmVkX3NlcXMgPSByYmluZChDT1ZJRF9hbGxfdW5jbHVzdGVyZWRfc2VxcywgQ09WSURfc2Vxc19saXN0JHVuY2x1c3RlcmVkX3NlcXNbW2ldXSkKfQpIQ19hbGxfY2x1c3RlcmVkX3NlcXMgPSBOVUxMCmZvcihpIGluIDE6bGVuZ3RoKEhDX3NlcXNfbGlzdCRjbHVzdGVyZWRfc2VxcykpewogIEhDX2FsbF9jbHVzdGVyZWRfc2VxcyA9IHJiaW5kKEhDX2FsbF9jbHVzdGVyZWRfc2VxcywgSENfc2Vxc19saXN0JGNsdXN0ZXJlZF9zZXFzW1tpXV0pCn0KSENfYWxsX3VuY2x1c3RlcmVkX3NlcXMgPSBOVUxMCmZvcihpIGluIDE6bGVuZ3RoKEhDX3NlcXNfbGlzdCR1bmNsdXN0ZXJlZF9zZXFzKSl7CiAgSENfYWxsX3VuY2x1c3RlcmVkX3NlcXMgPSByYmluZChIQ19hbGxfdW5jbHVzdGVyZWRfc2VxcywgSENfc2Vxc19saXN0JHVuY2x1c3RlcmVkX3NlcXNbW2ldXSkKfQpwaWUuZnJlcS5wbG90KGNsdXN0ZXJlZF9zZXFzID0gQ09WSURfYWxsX2NsdXN0ZXJlZF9zZXFzLCBjb2xuYW1lID0gInZfY2FsbCIpCnBpZS5mcmVxLnBsb3QoY2x1c3RlcmVkX3NlcXMgPSBIQ19hbGxfY2x1c3RlcmVkX3NlcXMsIGNvbG5hbWUgPSAidl9jYWxsIikKYGBgCmBgYHtyfQojIyAyLjMuMiBIZWF0bWFwOiBWLUogZ2VuZSBwYWlyCiMgSGVhdG1hcCBzaG93aW5nIHRoZSBWLUogZ2VuZSBwYWlyIGZyZXF1ZW5jeSBvZiBjbHVzdGVyZWQgc2VxdWVuY2VzCiMgKDEpIHNpbmdsZSBzYW1wbGUuCnZqcGFpci5zYW1wbGUucGxvdChjbHVzdGVyZWRfc2VxcyA9IENPVklEXzAxX2NsdXN0ZXJlZF9zZXFzKQpgYGAKYGBge3J9CiMgKDIpIG11bHRpcGxlIHNhbXBsZXMgaW4gYSBncm91cC4KdmpwYWlyLnNhbXBsZS5wbG90KGNsdXN0ZXJlZF9zZXFzID0gQ09WSURfYWxsX2NsdXN0ZXJlZF9zZXFzKQp2anBhaXIuc2FtcGxlLnBsb3QoY2x1c3RlcmVkX3NlcXMgPSBIQ19hbGxfY2x1c3RlcmVkX3NlcXMpCmBgYApgYGB7cn0KIyMgMi40IEp1bmN0aW9uIGxlbmd0aCBkaXN0cmlidXRpb24KIyBIaXN0b2dyYW0gYW5kIGRlbnNpdHkgcGxvdCBzaG93aW5nIHRoZSBsZW5ndGggZGlzdHJpYnV0aW9uIG9mIGp1bmN0aW9uIGFtaW5vIGFjaWQgb2YgY2x1c3RlcmVkIHNlcXVlbmNlcy4KIyAoMSkgc2luZ2xlIHNhbXBsZQpsZW4uc2FtcGxlLnBsb3QoY2x1c3RlcmVkX3NlcXMgPSBDT1ZJRF8wMV9jbHVzdGVyZWRfc2VxcykKIyAoMikgbXVsdGlwbGUgc2FtcGxlcyBpbiBhIGdyb3VwCmxlbi5zYW1wbGUucGxvdChjbHVzdGVyZWRfc2VxcyA9IENPVklEX2FsbF9jbHVzdGVyZWRfc2VxcykKIyBEZW5zaXR5IHJpZGdlcyBzaG93aW5nIHRoZSBsZW5ndGggZGlzdHJpYnV0aW9ucyBvZiBqdW5jdGlvbiBhbWlubyBhY2lkIG9mIGNsdXN0ZXJlZCBzZXF1ZW5jZXMgYW5kIHVuY2x1c3RlcmVkIHNlcXVlbmNlcy4KIyBTdGF0aXN0aWNhbCBjb21wYXJpc29ucyBhcmUgY2FycmllZCBvdXQgYnkgdGhlIHR3by1zaWRlZCBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0LgojICgxKSBzaW5nbGUgc2FtcGxlCmxlbi5jbHVzdGVyZWQucGxvdChjbHVzdGVyZWRfc2VxcyA9IENPVklEXzAxX2NsdXN0ZXJlZF9zZXFzLAogICAgICAgICAgICAgICAgICAgdW5jbHVzdGVyZWRfc2VxcyA9IENPVklEXzAxX3VuY2x1c3RlcmVkX3NlcXMpCiMgKDIpIG11bHRpcGxlIHNhbXBsZXMgaW4gYSBncm91cApsZW4uY2x1c3RlcmVkLnBsb3QoY2x1c3RlcmVkX3NlcXMgPSBDT1ZJRF9hbGxfY2x1c3RlcmVkX3NlcXMsCiAgICAgICAgICAgICAgICAgICB1bmNsdXN0ZXJlZF9zZXFzID0gQ09WSURfYWxsX3VuY2x1c3RlcmVkX3NlcXMpCmBgYApgYGB7cn0KIyMgMi41IENsYXNzIHN3aXRjaCByZWNvbWJpbmF0aW9uIChDU1IpIG5ldHdvcmsKIyBWaXN1YWxpemF0aW9uIG9mIGlzb3R5cGUgY28tb2NjdXJyZW5jZSB3aXRoaW4gY2x1c3RlcnMgZnJvbSBhIHNhbXBsZS4KIyBDaXJjbGUgc2l6ZSByZXByZXNlbnRzIHRoZSBudW1iZXIgb2Ygc2VxdWVuY2VzIGNhcnJ5aW5nIGEgZ2l2ZW4gaXNvdHlwZS4KIyBMaW5lcyBjb25uZWN0aW5nIHR3byBjaXJjbGVzIGluZGljYXRlIHRoZSBlbnJpY2htZW50IGxldmVsIG9mIG9ic2VydmluZyBzd2l0Y2hlcyBpbiB0aGUgdHdvIGNvcnJlc3BvbmRpbmcgaW1tdW5vZ2xvYnVsaW4gc3ViY2xhc3Nlcy4KIyBUaGUgZW5yaWNobWVudCBsZXZlbCBpcyB0aGUgcmF0aW8gb2Ygb2JzZXJ2ZWQgYW5kIGV4cGVjdGVkIHN3aXRjaGVzIGlmIGltbXVub2dsb2J1bGluIGlzb3R5cGVzIGFyZSBhc3N1bWVkIHRvIGJlIGluZGVwZW5kZW50bHkgZGlzdHJpYnV0ZWQgYW1vbmcgY2x1c3Rlci4KIyBNYXRyaXggb2YgdmFsdWVzIG9mIGNvbm5lY3RlZCBlZGdlcyBiZXR3ZWVuIGNsdXN0ZXJlZCBzZXF1ZW5jZXMgaW4gZGlmZmVyZW50IGlzb3R5cGVzIGlzIHByaW50ZWQuCkNTUi5zYW1wbGUucGxvdChiY3JfY2x1c3RlcnMgPSBDT1ZJRF8wMV9jbHVzdGVycykKQ1NSLnNhbXBsZS5wbG90KGJjcl9jbHVzdGVycyA9IEhDXzAxX2NsdXN0ZXJzKQpgYGAKCmBgYHtyfQojIyMgMi42IE5ldXRyYWxpemluZyBhbnRpYm9keSAoTkFiKSBzZXF1ZW5jZSBxdWVyeQojIyAyLjYuMSBMb2FkIHRoZSBwdWJsaWMgYW50aWJvZHkgZGF0YWJhc2UgdG8gZ2V0IHRoZSBpbmZvcm1hdGlvbiBvZiBuZXV0cmFsaXppbmcgYW50aWJvZHkgKE5BYikgc2VxdWVuY2VzLgojIEhlcmUgaXMgYW4gZXhhbXBsZSBvZiB0aGUgQ29yb25hdmlydXMgQW50aWJvZHkgRGF0YWJhc2UgKENvVi1BYkRhYikuCkNvVl9BYkRhYiA9IHJlYWQuY3N2KCJleGFtcGxlL0NvVi1BYkRhYl8xMzA2MjMuY3N2IikKIyMgMi42LjIgTkFiIHF1ZXJ5CiMgUXVlcnkgdGhlIGNvcnJlc3BvbmRpbmcgc2VxdWVuY2UgZnJvbSB0aGUgcHVibGljIGFudGlib2R5IGRhdGFiYXNlLgojIFRoZSBwYXJhbWV0ZXIgIm1ldGhvZCIgcmVwcmVzZW50cyB0aGUgQ0RSSDMgbWF0Y2hpbmcgbWV0aG9kLgojIEl0IGNhbiBiZSAiTkEiIGZvciBwZXJmZWN0IG1hdGNoLCAiaGFtbWluZyIgZm9yIGhhbW1pbmcgZGlzdGFuY2Ugb3IgImx2IiBmb3IgTGV2ZW5zaHRlaW4gZGlzdGFuY2UuIERlZmF1bHRzIHRvICJOQSIuCiMgVGhlIHBhcmFtZXRlciAic3BlY2llcyIgY2FuIGJlICJNb3VzZSIgb3IgIkh1bWFuIi4gRGVmYXVsdHMgdG8gIkh1bWFuIi4KIyBUaGUgcGFyYW1ldGVyICJtYXhEaXN0IiByZXByZXNlbnRzIHRoZSBtYXhpbXVtIGRpc3RhbmNlIGFsbG93ZWQgZm9yIG1hdGNoaW5nIHdoZW4gdGhlIGFyZ3VtZW50ICJtZXRob2QiIGlzICJoYW1taW5nIiBvciAibHYiLiBEZWZhdWx0cyB0byAiTkEiLgojIGV4YW1wbGUgdG8gcGVyZmVjdCBtYXRjaApodW1hbl9wZXJmZWN0X21hdGNoIDwtIE5BYi5xdWVyeShiY3JfY2x1c3RlcnMgPSBDT1ZJRF8wMV9jbHVzdGVycywgQWJEYWIgPSBDb1ZfQWJEYWIsIG1ldGhvZCA9IE5BLCBtYXhEaXN0ID0gTkEsIHNwZWNpZXMgPSAiSHVtYW4iKQpoZWFkKGh1bWFuX3BlcmZlY3RfbWF0Y2gpCmBgYAoKYGBge3J9CiMgZXhhbXBsZSB3aXRoIHBlcmZlY3QgbWF0Y2ggaW4gIk1vdXNlIiBzcGVjaWVzCm1vdXNlX3BlcmZlY3RfbWF0Y2ggPC0gTkFiLnF1ZXJ5KGJjcl9jbHVzdGVycyA9IENPVklEXzAxX2NsdXN0ZXJzLCBBYkRhYiA9IENvVl9BYkRhYiwgbWV0aG9kID0gTkEsIG1heERpc3QgPSBOQSwgc3BlY2llcyA9ICJNb3VzZSIpCmBgYApgYGB7cn0KIyBleGFtcGxlIHdpdGggZnV6enkgbWF0Y2hpbmcgd2l0aCAiaGFtbWluZyIgbWV0aG9kIGFuZCBtYXggZGlzdGFuY2Ugb2YgMQpodW1hbl9oYW1taW5nXzFfbWF0Y2ggPC0gTkFiLnF1ZXJ5KGJjcl9jbHVzdGVycyA9IENPVklEXzAxX2NsdXN0ZXJzLCBBYkRhYiA9IENvVl9BYkRhYiwgbWV0aG9kID0gImhhbW1pbmciLCBtYXhEaXN0ID0gMSwgc3BlY2llcyA9ICJIdW1hbiIpCmBgYAoKYGBge3J9CiMjIDMuIEludGVyIGdyb3VwIGFuYWx5c2lzCiMjIDMuMSBWL0ogZ2VuZSB1c2FnZQojIyAzLjEuMSBCb3hwbG90OiBWL0ogZ2VuZQojIEJveHBsb3Qgc2hvd2luZyB0aGUgVi9KIGdlbmUgdXNhZ2Ugb2YgdGhlIGNsdXN0ZXJlZCBzZXF1ZW5jZXMgYmV0d2VlbiB0d28gZ3JvdXBzLgojIFRoZSBwYXJhbWV0ZXIgImNvbG5hbWUiIGNhbiBiZSAidl9jYWxsIiBmb3IgViBnZW5lIG9yICJqX2NhbGwiIGZvciBKIGdlbmUuCiMgU3RhdGlzdGljYWwgY29tcGFyaXNvbnMgYXJlIGNhcnJpZWQgb3V0IGJ5IHRoZSB0d28tc2lkZWQgV2lsY294b24gcmFuay1zdW0gdGVzdC4KZ2VuZS5mcmUucGxvdChncm91cDFfc2Vxc19saXN0ID0gQ09WSURfc2Vxc19saXN0LAogICAgICAgICAgICAgIGdyb3VwMV9hbGxfY2x1c3RlcmVkX3NlcXMgPSBDT1ZJRF9hbGxfY2x1c3RlcmVkX3NlcXMsCiAgICAgICAgICAgICAgZ3JvdXAxX2xhYmVsID0gIkNPVklELTE5IiwKICAgICAgICAgICAgICBncm91cDJfc2Vxc19saXN0ID0gSENfc2Vxc19saXN0LAogICAgICAgICAgICAgIGdyb3VwMl9hbGxfY2x1c3RlcmVkX3NlcXMgPSBIQ19hbGxfY2x1c3RlcmVkX3NlcXMsCiAgICAgICAgICAgICAgZ3JvdXAyX2xhYmVsID0gIkhDIiwKICAgICAgICAgICAgICBjb2xuYW1lID0gInZfY2FsbCIpCmdlbmUuZnJlLnBsb3QoZ3JvdXAxX3NlcXNfbGlzdCA9IENPVklEX3NlcXNfbGlzdCwKICAgICAgICAgICAgICBncm91cDFfYWxsX2NsdXN0ZXJlZF9zZXFzID0gQ09WSURfYWxsX2NsdXN0ZXJlZF9zZXFzLAogICAgICAgICAgICAgIGdyb3VwMV9sYWJlbCA9ICJDT1ZJRC0xOSIsCiAgICAgICAgICAgICAgZ3JvdXAyX3NlcXNfbGlzdCA9IEhDX3NlcXNfbGlzdCwKICAgICAgICAgICAgICBncm91cDJfYWxsX2NsdXN0ZXJlZF9zZXFzID0gSENfYWxsX2NsdXN0ZXJlZF9zZXFzLAogICAgICAgICAgICAgIGdyb3VwMl9sYWJlbCA9ICJIQyIsCiAgICAgICAgICAgICAgY29sbmFtZSA9ICJqX2NhbGwiKQpgYGAKCgpgYGB7cn0KIyMgMy4xLjIgSGVhdG1hcDogVi1KIGdlbmUgcGFpcgojIEhlYXRtYXAgc2hvd2luZyB0aGUgZm9sZCBjaGFuZ2Ugb2YgVi1KIGdlbmUgcGFpciBmcmVxdWVuY3kgb2YgY2x1c3RlcmVkIHNlcXVlbmNlcyBiZXR3ZWVuIHR3byBncm91cHMuCiMgTG9nIGZvbGQgY2hhbmdlIChsb2cgRkMpIGlzIGNhbGN1bGF0ZWQgYXMgdGhlIGxvZzIgcmF0aW8gb2YgdGhlIGF2ZXJhZ2UgdmFsdWVzIGJldHdlZW4gZ3JvdXAxIGFuZCBncm91cDIgc2FtcGxlcy4KIyBTdGF0aXN0aWNhbCBjb21wYXJpc29ucyBhcmUgY2FycmllZCBvdXQgYnkgdGhlIHR3by1zaWRlZCBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0LgojIEZEUiBjb3JyZWN0aW9uIHdhcyBwZXJmb3JtZWQgd2l0aCB0aGUgQmVuamFtaW5p4oCTSG9jaGJlcmcgcHJvY2VkdXJlLgojIFRoZSBWLUogZ2VuZSBwYWlyIGZyZXF1ZW5jeSBvZiBzYW1wbGVzIHdpdGggYSBmcmVxdWVuY3kgbGVzcyB0aGFuIHRoZSBtaW5pbXVtIHZhbHVlICgx4oCwKSBpcyBzZXQgdG8gdGhlIG1pbmltdW0gdmFsdWUuCnZqcGFpci5ncm91cC5wbG90KGdyb3VwMV9zZXFzX2xpc3QgPSBDT1ZJRF9zZXFzX2xpc3QsCiAgICAgICAgICAgICAgICAgIGdyb3VwMV9hbGxfY2x1c3RlcmVkX3NlcXMgPSBDT1ZJRF9hbGxfY2x1c3RlcmVkX3NlcXMsCiAgICAgICAgICAgICAgICAgIGdyb3VwMV9sYWJlbCA9ICJDT1ZJRC0xOSIsCiAgICAgICAgICAgICAgICAgIGdyb3VwMl9zZXFzX2xpc3QgPSBIQ19zZXFzX2xpc3QsCiAgICAgICAgICAgICAgICAgIGdyb3VwMl9hbGxfY2x1c3RlcmVkX3NlcXMgPSBIQ19hbGxfY2x1c3RlcmVkX3NlcXMsCiAgICAgICAgICAgICAgICAgIGdyb3VwMl9sYWJlbCA9ICJIQyIpCmBgYAoKYGBge3J9CiMjIDMuMiBKdW5jdGlvbiBsZW5ndGgKIyBEZW5zaXR5IHJpZGdlcyBzaG93aW5nIHRoZSBsZW5ndGggZGlzdHJpYnV0aW9uIG9mIGp1bmN0aW9uIGFtaW5vIGFjaWQgb2YgY2x1c3RlcmVkIHNlcXVlbmNlcyBiZXR3ZWVuIHR3byBncm91cHMuCiMgU3RhdGlzdGljYWwgY29tcGFyaXNvbnMgYXJlIGNhcnJpZWQgb3V0IGJ5IHRoZSB0d28tc2lkZWQgV2lsY294b24gcmFuay1zdW0gdGVzdC4KbGVuLmdyb3VwLnBsb3QoZ3JvdXAxX2FsbF9jbHVzdGVyZWRfc2VxcyA9IENPVklEX2FsbF9jbHVzdGVyZWRfc2VxcywgZ3JvdXAxX2xhYmVsID0gIkNPVklELTE5IiwKICAgICAgICAgICAgICAgZ3JvdXAyX2FsbF9jbHVzdGVyZWRfc2VxcyA9IEhDX2FsbF9jbHVzdGVyZWRfc2VxcywgZ3JvdXAyX2xhYmVsID0gIkhDIikKYGBgCmBgYHtyfQojIyAzLjMgRGl2ZXJzaXR5IGFuYWx5c2lzCiMjIDMuMy4xIE51bWJlciBhbmQgc2l6ZSBvZiBjbHVzdGVycwojIEJ1YmJsZSBwbG90IHNob3dpbmcgdGhlIHNpemUgYW5kIG51bWJlciBvZiBjbHVzdGVycyBiZXR3ZWVuIHR3byBncm91cHMuCmNsdS5zaXplLnBsb3QoY2x1c3RlcnNfbGlzdDEgPSBDT1ZJRF9jbHVzdGVyc19saXN0LCBncm91cDFfbGFiZWwgPSAiQ09WSUQtMTkiLAogICAgICAgICAgICAgIGNsdXN0ZXJzX2xpc3QyID0gSENfY2x1c3RlcnNfbGlzdCwgZ3JvdXAyX2xhYmVsID0gIkhDIikKYGBgCmBgYHtyfQojIyAzLjMuMiBUY2YyMCBzY29yZQojIFRjZjIwIHNjb3JlIHJlcHJlc2VudHMgdGhlIHByb3BvcnRpb24gb2Ygc2VxdWVuY2VzIGF0dHJpYnV0ZWQgdG8gdGhlIHRvcCAyMCBjbG9uYWwgZmFtaWxpZXMgb3V0IG9mIHRoZSB0b3RhbCBudW1iZXIgb2YgQkNSIHNlcXVlbmNlcy4KIyBCb3hwbG90IHNob3dpbmcgdGhlIFRjZjIwIHNjb3JlcyBiZXR3ZWVuIHR3byBncm91cHMuCiMgU3RhdGlzdGljYWwgY29tcGFyaXNvbnMgYXJlIGNhcnJpZWQgb3V0IGJ5IHRoZSB0d28tc2lkZWQgV2lsY294b24gcmFuay1zdW0gdGVzdC4KVGNmMjAucGxvdChjbHVzdGVyc19saXN0MSA9IENPVklEX2NsdXN0ZXJzX2xpc3QsIGdyb3VwMV9sYWJlbCA9ICJDT1ZJRC0xOSIsCiAgICAgICAgICAgY2x1c3RlcnNfbGlzdDIgPSBIQ19jbHVzdGVyc19saXN0LCBncm91cDJfbGFiZWwgPSAiSEMiKQpgYGAKYGBge3J9CiMjIDMuNCBTb21hdGljIGh5cGVybXV0YXRpb24gKFNITSkgYW5hbHlzaXMKIyBDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgU0hNIHJhdGlvIG9mIGFsbCBjbHVzdGVycyBpbiBlYWNoIHNhbXBsZS4KIyBUaGUgY2FsY3VsYXRpb24gb2YgU0hNIHJhdGlvcyBtYXkgdGFrZSBhIHdoaWxlLgpTSE1fZGYgPSBTSE0uY2FsY3VsYXRpb24oY2x1c3RlcnNfbGlzdDEgPSBDT1ZJRF9jbHVzdGVyc19saXN0LCBncm91cDFfbGFiZWwgPSAiQ09WSUQtMTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnNfbGlzdDIgPSBIQ19jbHVzdGVyc19saXN0LCBncm91cDJfbGFiZWwgPSAiSEMiKQpgYGAKCmBgYHtyfQojIEJveHBsb3Qgc2hvd2luZyB0aGUgU0hNIHJhdGlvcyBiZXR3ZWVuIHR3byBncm91cHMuCiMgU3RhdGlzdGljYWwgY29tcGFyaXNvbnMgYXJlIGNhcnJpZWQgb3V0IGJ5IHRoZSB0d28tc2lkZWQgV2lsY294b24gcmFuay1zdW0gdGVzdC4KU0hNLnBsb3QoU0hNX2RmID0gU0hNX2RmKQpgYGAKCgpgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIFNITSByYXRpb3Mgb2YgY2x1c3RlcmVkIHNlcXVlbmNlcyBpbiBkaWZmZXJlbnQgaXNvdHlwZXMgaW4gZWFjaCBzYW1wbGUuCiMgVGhlIGNhbGN1bGF0aW9uIG9mIFNITSByYXRpb3MgbWF5IHRha2UgYSB3aGlsZS4KU0hNX2lzb19kZiA9IFNITS5pc28uY2FsY3VsYXRpb24oY2x1c3RlcnNfbGlzdDEgPSBDT1ZJRF9jbHVzdGVyc19saXN0LCBncm91cDFfbGFiZWwgPSAiQ09WSUQtMTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyc19saXN0MiA9IEhDX2NsdXN0ZXJzX2xpc3QsIGdyb3VwMl9sYWJlbCA9ICJIQyIpCmBgYAoKYGBge3J9CiMgQm94cGxvdCBzaG93aW5nIHRoZSBTSE0gcmF0aW9zIG9mIGNsdXN0ZXJlZCBzZXF1ZW5jZXMgaW4gZGlmZmVyZW50IGlzb3R5cGVzIGJldHdlZW4gdHdvIGdyb3Vwcy4KIyBTdGF0aXN0aWNhbCBjb21wYXJpc29ucyBhcmUgY2FycmllZCBvdXQgYnkgdGhlIHR3by1zaWRlZCBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0LgpTSE0uaXNvLnBsb3QoU0hNX2lzb19kZiA9IFNITV9pc29fZGYpCmBgYAoKCmBgYHtyfQojIyMgMy41IE5BYiByYXRpbyBjYWxjdWxhdGlvbgojIyAzLjUuMSBMb2FkIHRoZSBwdWJsaWMgYW50aWJvZHkgZGF0YWJhc2UgdG8gZ2V0IHRoZSBpbmZvcm1hdGlvbiBvZiBuZXV0cmFsaXppbmcgYW50aWJvZHkgKE5BYikgc2VxdWVuY2VzLgojIEhlcmUgaXMgYW4gZXhhbXBsZSBvZiB0aGUgQ29yb25hdmlydXMgQW50aWJvZHkgRGF0YWJhc2UgKENvVi1BYkRhYikuCkNvVl9BYkRhYiA9IHJlYWQuY3N2KCJleGFtcGxlL0NvVi1BYkRhYl8xMzA2MjMuY3N2IikKIyBPYnRhaW4gdGhlIElHSFYgZ2VuZSwgSUdISiBnZW5lIGFuZCBDRFJIMyBvZiBhbGwgYW50aWJvZHkgc2VxdWVuY2VzCnYgPSBzYXBwbHkoc3Ryc3BsaXQoQ29WX0FiRGFiJEhlYXZ5LlYuR2VuZSwgIiAiKSwgZnVuY3Rpb24oeCkgeFsxXSkKaiA9IHNhcHBseShzdHJzcGxpdChDb1ZfQWJEYWIkSGVhdnkuSi5HZW5lLCAiICIpLCBmdW5jdGlvbih4KSB4WzFdKQpjZHIzID0gc2FwcGx5KHN0cnNwbGl0KENvVl9BYkRhYiRDRFJIMywgIiAiKSwgZnVuY3Rpb24oeCkgeFsxXSkKdmpjZHIzID0gdW5pcXVlKHBhc3RlKHYsIGosIGNkcjMpKQpgYGAKCmBgYHtyfQojIyAzLjUuMiBOQWIgcmF0aW8gY2FsY3VsYXRpb24KIyBOQWIgcmF0aW8gaXMgZXN0YWJsaXNoZWQgYXMgYW4gaW5kaWNhdG9yIG9mIHRoZSBwcm9wb3J0aW9uYWwgcHJldmFsZW5jZSBvZiBuZXV0cmFsaXppbmcgYW50aWJvZHkgc2VxdWVuY2VzIHdpdGhpbiBleHBhbmRlZCBjbG9ub3R5cGVzIGluIGVhY2ggc2FtcGxlLgojIEl0IGlzIGRlZmluZWQgYXMgdGhlIGZyYWN0aW9uIG9mIHRoZSBudW1iZXIgb2YgTkFiIHNlcXVlbmNlcyB3aXRoaW4gY2xvbmFsIGZhbWlsaWVzIHRvIHRoZSB0b3RhbCBudW1iZXIgb2YgTkFiIHNlcXVlbmNlcyBwcmVzZW50IGluIGVhY2ggc2FtcGxlLgpOQWJfcmF0aW9fZGYgPSBOQWIucmF0aW8uY2FsY3VsYXRpb24ocHJvX2RhdGFfbGlzdDEgPSBDT1ZJRF9wcm9fZGF0YV9saXN0LCBjbHVzdGVyc19saXN0MSA9IENPVklEX2NsdXN0ZXJzX2xpc3QsIGdyb3VwMV9sYWJlbCA9ICJDT1ZJRC0xOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9fZGF0YV9saXN0MiA9IEhDX3Byb19kYXRhX2xpc3QsIGNsdXN0ZXJzX2xpc3QyID0gSENfY2x1c3RlcnNfbGlzdCwgZ3JvdXAyX2xhYmVsID0gIkhDIiwgTkFiX3ZqY2RyMyA9IHZqY2RyMykKYGBgCgpgYGB7cn0KIyBCb3hwbG90IHNob3dpbmcgdGhlIE5BYiByYXRpb3MgYmV0d2VlbiB0aGUgdHdvIGdyb3Vwcy4KIyBTdGF0aXN0aWNhbCBjb21wYXJpc29ucyBhcmUgY2FycmllZCBvdXQgYnkgdGhlIHR3by1zaWRlZCBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0LgpOQWIucmF0aW8ucGxvdChOQWJfcmF0aW9fZGYpCmBgYAoK